﻿
Imports osi.root.delegates
Imports osi.root.lock
Imports osi.root.utils
Imports osi.root.formation
Imports osi.root.connector
Imports osi.root.threadpool
Imports osi.root.constants.error_handle

Public Class event_comb_async_operation
    Inherits event_comb

    Private ReadOnly e As Action(Of Boolean, IAsyncResult)
    Private ar As IAsyncResult
    Private finished As singleentry

    Private Shared Shadows Function current() As event_comb_async_operation
        Return cast(Of event_comb_async_operation)(event_comb.current())
    End Function

    <Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _
    Private Sub New(ByVal begin As Func(Of AsyncCallback, IAsyncResult),
                    ByVal [end] As Action(Of Boolean, IAsyncResult),
                    ByVal additional_jump As Int32)
        MyBase.New(New _do(Of Boolean)() _
                   {Function() As Boolean
                        Dim c As void = Nothing
                        c = wait()
                        'if the void from wait()'s return has been called before goto_next(),
                        'the goto_next() will not take effect
                        assert(Not begin Is Nothing)
                        Try
                            current().ar = begin(Sub(ar As IAsyncResult)
                                                     c()
                                                 End Sub)
                        Catch ex As Exception
                            raise_error(error_type.warning,
                                        "failed to begin ",
                                        invoke_method_name(begin),
                                        ", callstack, ",
                                        current().callstack(),
                                        ", ex ",
                                        ex.Message)
                        End Try
                        Return goto_next()
                    End Function,
                    Function() As Boolean
                        current().finish()
                        Return goto_end()
                    End Function},
                   additional_jump + 1)
        assert(Not [end] Is Nothing)
        e = [end]
        resetting = Sub()
                        failed_finish()
                        finished.release()
                    End Sub
        timeouting = AddressOf failed_finish
    End Sub

    <Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _
    Public Sub New(ByVal begin As Func(Of AsyncCallback, IAsyncResult),
                   ByVal [end] As Action(Of IAsyncResult))
        Me.New(begin,
               Sub(e As Boolean, ar As IAsyncResult)
                   assert(Not [end] Is Nothing)
                   [end](ar)
               End Sub,
               1)
    End Sub

    <Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _
    Public Shared Function ctor(Of T)(ByVal begin As Func(Of AsyncCallback, IAsyncResult),
                                      ByVal [end] As Func(Of IAsyncResult, T),
                                      Optional ByVal result As pointer(Of T) = Nothing) As event_comb_async_operation
        Return New event_comb_async_operation(begin,
                                              Sub(e As Boolean, ar As IAsyncResult)
                                                  Dim r As T = Nothing
                                                  assert(Not [end] Is Nothing)
                                                  r = [end](ar)
                                                  If Not e Then
                                                      eva(result, r)
                                                  End If
                                              End Sub,
                                              1)
    End Function

    Private Sub finish(ByVal e As Boolean)
        Try
            Me.e(e, ar)
        Catch ex As Exception
            raise_error(error_type.warning,
                        "failed to begin ",
                        invoke_method_name(Me.e),
                        ", callstack, ",
                        current().callstack(),
                        ", ex ",
                        ex.Message)
        End Try
    End Sub

    Private Sub failed_finish()
        If finished.mark_in_use() AndAlso Not ar Is Nothing Then
            async_result_destructor.queue(Sub()
                                              finish(True)
                                          End Sub)
        End If
    End Sub

    Private Sub finish()
        If finished.mark_in_use() Then
            assert(Not ar Is Nothing)
            finish(False)
        End If
    End Sub
End Class
